﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

using TowerDef_s_enseLibrary.enemy;
using TowerDef_s_enseLibrary.tower;
using TowerDef_s_enseLibrary.tower.arrowtower;
using TowerDef_s_enseLibrary.tower.slowtower;
using TowerDef_s_enseLibrary.tower.spiketower;
using TowerDef_s_enseLibrary.map;

namespace TowerDef_s_enseLibrary.player
{
    public class Player
    {
        #region variables

        private int _money = 5000;
        /// <summary>
        /// Get and set the money of the player
        /// </summary>
        public int Money
        {
            get
            {
                return _money;
            }
            set
            {
                _money = value;
            }
        }
        private int _lives = 30;
        /// <summary>
        /// Get and set the lives of the player
        /// </summary>
        public int Lives
        {
            get
            {
                return _lives;
            }
            set
            {
                _lives = value;
            }
        }
        private int _newTowerIndex;
        /// <summary>
        /// Set the index of a new tower
        /// </summary>
        public int NewTowerIndex
        {
            set
            {
                _newTowerIndex = value;
            }
        }
        private int _cellX;
        private int _cellY;
        private int _tileX;
        private int _tileY;

        private List<Tower> towers = new List<Tower>();

        private MouseState _mouseState; // Mouse state for the current frame
        private MouseState _oldState; // Mouse state for the previous frame

        // The type of tower to add.
        private string _newTowerType;
        /// <summary>
        /// Get and set the name of the new tower
        /// </summary>
        public string NewTowerType
        {
            set
            {
                _newTowerType = value;
            }
        }

        private Map _map;

        private Texture2D[] _towerTextures;
        private Texture2D _bulletTexture;

        #endregion variables

        #region functions

        /// <summary>
        /// Creates a new Player
        /// </summary>
        /// <param name="map">The map</param>
        /// <param name="towerTextures">The tower Texture list</param>
        /// <param name="bulletTexture">The bullet Texture list</param>
        public Player(Map map, Texture2D[] towerTextures, Texture2D bulletTexture)
        {
            this._map = map;
            this._towerTextures = towerTextures;
            this._bulletTexture = bulletTexture;
        }

        /// <summary>
        /// Checks if the current cell is clear
        /// </summary>
        /// <returns>Returns true if the Cell is clear</returns>
        private bool IsCellClear()
        {
            bool inBounds = _cellX >= 0 && _cellY >= 0&& // Make sure tower is within limits
                _cellX < _map.Width && _cellY < _map.Height;

            bool spaceClear = true;

            foreach (Tower tower in towers) // Check that there is no tower here
            {
                spaceClear = (tower.Position != new Vector2(_tileX, _tileY));
                if (!spaceClear)
                    break;
            }

            bool onPath = (_map.GetIndex(_cellX, _cellY) != 2);
            return inBounds && spaceClear && onPath;
        }

        /// <summary>
        /// Checks if the mouse is over the map
        /// </summary>
        /// <param name="mouseState">The mouse state</param>
        /// <returns>Returns true if mouse is over the map</returns>
        private bool IsMouseOverMap(MouseState mouseState)
        {
            bool inBounds = (mouseState.X >= 16 && mouseState.Y >= 48) && (mouseState.X < _map.Width*32+16 && mouseState.Y < _map.Height*32+48);
            return inBounds;
        }

        /// <summary>
        /// Adds a tower to the player's collection
        /// </summary>
        public void AddTower()
        {
            Tower towerToAdd = null;

            switch(_newTowerType)
            {
                case "Arrow Tower":
                {
                    towerToAdd = new ArrowTower(_towerTextures[_newTowerIndex], _bulletTexture, new Vector2(_tileX + 16, _tileY + 48));
                    break;
                }
                case "Slow Tower":
                {
                    towerToAdd = new SlowTower(_towerTextures[_newTowerIndex], _bulletTexture, new Vector2(_tileX + 16, _tileY + 48));
                    break;
                }
                case "Spike Tower":
                {
                    towerToAdd = new SpikeTower(_towerTextures[_newTowerIndex], _bulletTexture, new Vector2(_tileX + 16, _tileY + 48));
                    break;
                }
            }

            // Only add the tower if there is a space and if the player can afford it
            if(IsCellClear() == true && towerToAdd.Cost <= _money)
            {
                towers.Add(towerToAdd);
                _money -= towerToAdd.Cost;

                // Reset the newTowerType field
                _newTowerType = string.Empty;
            }
            else
            {
                _newTowerType = string.Empty;
            }
        }

        /// <summary>
        /// Draws a preview of the chosen tower at the mouse icon
        /// </summary>
        /// <param name="spriteBatch">A group of sprite settings</param>
        public void DrawPreview(SpriteBatch spriteBatch)
        {
            // Draw the tower preview.
            if(string.IsNullOrEmpty(_newTowerType) == false)
            {
                var cellX = (int)(_mouseState.X / 32); // Convert the position of the mouse
                var cellY = (int)(_mouseState.Y / 32); // from array space to _map space

                var tileX = cellX * 32+16; // Convert from array space to _map space
                var tileY = cellY * 32+48; // Convert from array space to _map space

                Texture2D previewTexture = _towerTextures[_newTowerIndex];

                _mouseState = Mouse.GetState();
                if(IsMouseOverMap(_mouseState) == true) // shows preview towers only on map
                {
                    spriteBatch.Draw(previewTexture, new Rectangle(tileX, tileY, previewTexture.Width, previewTexture.Height), Color.White);
                }
            }
        }

        /// <summary>
        /// Updates the player class in matters of the game time
        /// </summary>
        /// <param name="gameTime">The current game time</param>
        /// <param name="enemies">The list of the _enemies</param>
        public void Update(GameTime gameTime, List<Enemy> enemies)
        {
            _cellX = (int)(_mouseState.X / 32); // Convert the position of the mouse
            _cellY = (int)(_mouseState.Y / 32); // from array space to _map space
            _tileX = _cellX * 32; // Convert from array space to _map space
            _tileY = _cellY * 32; // Convert from array space to _map space

            if(_mouseState.LeftButton == ButtonState.Released && _oldState.LeftButton == ButtonState.Pressed)
            {
                if(string.IsNullOrEmpty(_newTowerType) == false)
                {
                    AddTower();
                }
            }

            foreach(Tower tower in towers)
            {
                // Make sure the tower has no targets.
                if(tower.HasTarget == false)
                {
                    tower.GetClosestEnemy(enemies);
                }
                tower.Update(gameTime);
            }

            _oldState = _mouseState; // Set the oldState so it becomes the state of the previous frame.
        }

        /// <summary>
        /// Draws the tower at the map
        /// </summary>
        /// <param name="spriteBatch">A group of sprite settings</param>
        public void Draw(SpriteBatch spriteBatch)
        {
            foreach (Tower tower in towers)
            {
                tower.Draw(spriteBatch);
            }
        }

        #endregion functions

        #region events



        #endregion events
    }
}
